home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / xpuzzles.3 / xpuzzles / xpuzzles-5.3.1 / xoct / Oct.c < prev    next >
C/C++ Source or Header  |  1996-02-05  |  63KB  |  2,157 lines

  1. /*
  2. # X-BASED OCTAHEDRON
  3. #
  4. #  Oct.c
  5. #
  6. ###
  7. #
  8. #  Copyright (c) 1994 - 96    David Albert Bagley, bagleyd@hertz.njit.edu
  9. #
  10. #                   All Rights Reserved
  11. #
  12. #  Permission to use, copy, modify, and distribute this software and
  13. #  its documentation for any purpose and without fee is hereby granted,
  14. #  provided that the above copyright notice appear in all copies and
  15. #  that both that copyright notice and this permission notice appear in
  16. #  supporting documentation, and that the name of the author not be
  17. #  used in advertising or publicity pertaining to distribution of the
  18. #  software without specific, written prior permission.
  19. #
  20. #  This program is distributed in the hope that it will be "playable",
  21. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  23. #
  24. */
  25.  
  26. /* Methods file for Oct */
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #ifdef VMS
  31. #include <unixlib.h>
  32. #else
  33. #ifndef apollo
  34. #include <unistd.h>
  35. #endif
  36. #endif
  37. #include <X11/IntrinsicP.h>
  38. #include <X11/Intrinsic.h>
  39. #include <X11/StringDefs.h>
  40. #include <X11/CoreP.h>
  41. #include "OctP.h"
  42.  
  43. #ifndef DATAFILE
  44. #define DATAFILE "/usr/games/lib/oct.data"
  45. #endif
  46.  
  47. #define NOTDIR(x) ((x==CW)?CCW:CW)
  48.  
  49. typedef struct _RTT
  50. {
  51.   int row, trbl, tlbr;
  52. } RTT;
  53.  
  54. static void InitializeOct();
  55. static void ExposeOct();
  56. static void ResizeOct();
  57. static void DestroyOct();
  58. static Boolean SetValuesOct();
  59. static void QuitOct();
  60. static void PracticeOct();
  61. static void PracticeOctMaybe();
  62. static void RandomizeOct();
  63. static void RandomizeOctMaybe();
  64. static void GetOct();
  65. static void WriteOct();
  66. static void UndoOct();
  67. static void SolveOct();
  68. static void IncrementOct();
  69. static void DecrementOct();
  70. static void OrientizeOct();
  71. static void Period3ModeOct();
  72. static void Period4ModeOct();
  73. static void BothModeOct();
  74. static void StickyModeOct();
  75. static void MoveOctTl();
  76. static void MoveOctTop();
  77. static void MoveOctTr();
  78. static void MoveOctLeft();
  79. static void MoveOctCw();
  80. static void MoveOctRight();
  81. static void MoveOctBl();
  82. static void MoveOctBottom();
  83. static void MoveOctBr();
  84. static void MoveOctCcw();
  85. static void MoveOctInput();
  86. static void SelectOct();
  87. static void ReleaseOct();
  88. static void GetColor();
  89. static void MoveControlCb();
  90. static void CheckPolyhedrons();
  91. static void ResetPolyhedrons();
  92. static void ResizePolyhedrons();
  93. static int SelectPolyhedrons();
  94. static int NarrowSelection();
  95. static int PositionPolyhedrons();
  96. static void MoveNoPolyhedrons();
  97. static void PracticePolyhedrons();
  98. static void RandomizePolyhedrons();
  99. static void MovePolyhedrons();
  100. static void RotateFace();
  101. /* RTT : Row, Top right bottom left, Top left bottom right */
  102. static void ReadRTT();
  103. static void RotateRTT();
  104. static void ReverseRTT();
  105. static void WriteRTT();
  106. static void DrawFrame();
  107. static void DrawTriangle();
  108. static void DrawOrientLine();
  109. static int Length();
  110. static int CheckMoveDir();
  111. static RTT ToRTT();
  112. static int ToPosition();
  113. static int Sqrt();
  114.  
  115. #ifdef DEBUG
  116. static void PrintOcta();
  117. static void PrintFace();
  118. static void PrintRow();
  119. #endif
  120.  
  121. static char defaultTranslationsOct[] =
  122.   "<KeyPress>q: Quit()\n\
  123.    Ctrl<KeyPress>C: Quit()\n\
  124.    <KeyPress>KP_Divide: MoveCcw()\n\
  125.    <KeyPress>Home: MoveTl()\n\
  126.    <KeyPress>KP_7: MoveTl()\n\
  127.    <KeyPress>R7: MoveTl()\n\
  128.    <KeyPress>Up: MoveTop()\n\
  129.    <KeyPress>KP_8: MoveTop()\n\
  130.    <KeyPress>R8: MoveTop()\n\
  131.    <KeyPress>Prior: MoveTr()\n\
  132.    <KeyPress>KP_9: MoveTr()\n\
  133.    <KeyPress>R9: MoveTr()\n\
  134.    <KeyPress>Left: MoveLeft()\n\
  135.    <KeyPress>KP_4: MoveLeft()\n\
  136.    <KeyPress>R10: MoveLeft()\n\
  137.    <KeyPress>Begin: MoveCw()\n\
  138.    <KeyPress>KP_5: MoveCw()\n\
  139.    <KeyPress>R11: MoveCw()\n\
  140.    <KeyPress>Right: MoveRight()\n\
  141.    <KeyPress>KP_6: MoveRight()\n\
  142.    <KeyPress>R12: MoveRight()\n\
  143.    <KeyPress>End: MoveBl()\n\
  144.    <KeyPress>KP_1: MoveBl()\n\
  145.    <KeyPress>R13: MoveBl()\n\
  146.    <KeyPress>Down: MoveBottom()\n\
  147.    <KeyPress>KP_2: MoveBottom()\n\
  148.    <KeyPress>R14: MoveBottom()\n\
  149.    <KeyPress>Next: MoveBr()\n\
  150.    <KeyPress>KP_3: MoveBr()\n\
  151.    <KeyPress>R15: MoveBr()\n\
  152.    <Btn1Down>: Select()\n\
  153.    <Btn1Up>: Release()\n\
  154.    <KeyPress>p: Practice()\n\
  155.    <Btn2Down>(2+): Practice()\n\
  156.    <Btn2Down>: PracticeMaybe()\n\
  157.    <KeyPress>r: Randomize()\n\
  158.    <Btn3Down>(2+): Randomize()\n\
  159.    <Btn3Down>: RandomizeMaybe()\n\
  160.    <KeyPress>g: Get()\n\
  161.    <KeyPress>w: Write()\n\
  162.    <KeyPress>u: Undo()\n\
  163.    <KeyPress>s: Solve()\n\
  164.    <KeyPress>i: Increment()\n\
  165.    <KeyPress>d: Decrement()\n\
  166.    <KeyPress>o: Orientize()\n\
  167.    <KeyPress>3: Period3()\n\
  168.    <KeyPress>4: Period4()\n\
  169.    <KeyPress>b: Both()\n\
  170.    <KeyPress>y: Sticky()";
  171.  
  172. static XtActionsRec actionsListOct[] =
  173. {
  174.   {"Quit", (XtActionProc) QuitOct},
  175.   {"MoveCcw", (XtActionProc) MoveOctCcw},
  176.   {"MoveTl", (XtActionProc) MoveOctTl},
  177.   {"MoveTop", (XtActionProc) MoveOctTop},
  178.   {"MoveTr", (XtActionProc) MoveOctTr},
  179.   {"MoveLeft", (XtActionProc) MoveOctLeft},
  180.   {"MoveCw", (XtActionProc) MoveOctCw},
  181.   {"MoveRight", (XtActionProc) MoveOctRight},
  182.   {"MoveBl", (XtActionProc) MoveOctBl},
  183.   {"MoveBottom", (XtActionProc) MoveOctBottom},
  184.   {"MoveBr", (XtActionProc) MoveOctBr},
  185.   {"Select", (XtActionProc) SelectOct},
  186.   {"Release", (XtActionProc) ReleaseOct},
  187.   {"Practice", (XtActionProc) PracticeOct},
  188.   {"PracticeMaybe", (XtActionProc) PracticeOctMaybe},
  189.   {"Randomize", (XtActionProc) RandomizeOct},
  190.   {"RandomizeMaybe", (XtActionProc) RandomizeOctMaybe},
  191.   {"Get", (XtActionProc) GetOct},
  192.   {"Write", (XtActionProc) WriteOct},
  193.   {"Undo", (XtActionProc) UndoOct},
  194.   {"Solve", (XtActionProc) SolveOct},
  195.   {"Increment", (XtActionProc) IncrementOct},
  196.   {"Decrement", (XtActionProc) DecrementOct},
  197.   {"Orientize", (XtActionProc) OrientizeOct},
  198.   {"Period3", (XtActionProc) Period3ModeOct},
  199.   {"Period4", (XtActionProc) Period4ModeOct},
  200.   {"Both", (XtActionProc) BothModeOct},
  201.   {"Sticky", (XtActionProc) StickyModeOct}
  202. };
  203.  
  204. static XtResource resourcesOct[] =
  205. {
  206.   /* Beware color values are swapped */
  207.   {XtNfaceColor0, XtCLabel, XtRString, sizeof(String),
  208.    XtOffset(OctWidget, oct.faceName[0]), XtRString, "Red"},
  209.   {XtNfaceColor1, XtCLabel, XtRString, sizeof(String),
  210.    XtOffset(OctWidget, oct.faceName[1]), XtRString, "Blue"},
  211.   {XtNfaceColor2, XtCLabel, XtRString, sizeof(String),
  212.    XtOffset(OctWidget, oct.faceName[2]), XtRString, "White"},
  213.   {XtNfaceColor3, XtCLabel, XtRString, sizeof(String),
  214.    XtOffset(OctWidget, oct.faceName[3]), XtRString, "Magenta"},
  215.   {XtNfaceColor4, XtCLabel, XtRString, sizeof(String),
  216.    XtOffset(OctWidget, oct.faceName[4]), XtRString, "Orange"},
  217.   {XtNfaceColor5, XtCLabel, XtRString, sizeof(String),
  218.    XtOffset(OctWidget, oct.faceName[5]), XtRString, "Pink"},
  219.   {XtNfaceColor6, XtCLabel, XtRString, sizeof(String),
  220.    XtOffset(OctWidget, oct.faceName[6]), XtRString, "Green"},
  221.   {XtNfaceColor7, XtCLabel, XtRString, sizeof(String),
  222.    XtOffset(OctWidget, oct.faceName[7]), XtRString, "Yellow"},
  223.   {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  224.    XtOffset(OctWidget, oct.foreground), XtRString, XtDefaultForeground},
  225.   {XtNpieceBorder, XtCColor, XtRPixel, sizeof(Pixel),
  226.    XtOffset(OctWidget, oct.borderColor), XtRString, XtDefaultForeground},
  227.   {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
  228.    XtOffset(OctWidget, core.width), XtRString, "200"},
  229.   {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
  230.    XtOffset(OctWidget, core.height), XtRString, "400"},
  231.   {XtNmono, XtCMono, XtRBoolean, sizeof(Boolean),
  232.    XtOffset(OctWidget, oct.mono), XtRString, "FALSE"},
  233.   {XtNsize, XtCSize, XtRInt, sizeof(int),
  234.    XtOffset(OctWidget, oct.size), XtRString, "3"}, /*DEFAULTOCTAS*/
  235.   {XtNsticky, XtCSticky, XtRBoolean, sizeof(Boolean),
  236.    XtOffset(OctWidget, oct.sticky), XtRString, "FALSE"},
  237.   {XtNmode, XtCMode, XtRInt, sizeof(int),
  238.    XtOffset(OctWidget, oct.mode), XtRString, "4"}, /*DEFAULTMODE*/
  239.   {XtNorient, XtCOrient, XtRBoolean, sizeof(Boolean),
  240.    XtOffset(OctWidget, oct.orient), XtRString, "FALSE"}, /*DEFAULTORIENT*/
  241.   {XtNpractice, XtCPractice, XtRBoolean, sizeof(Boolean),
  242.    XtOffset(OctWidget, oct.practice), XtRString, "FALSE"}, /*DEFAULTPRACTICE*/
  243.   {XtNstart, XtCBoolean, XtRBoolean, sizeof(Boolean),
  244.    XtOffset(OctWidget, oct.started), XtRString, "FALSE"},
  245.   {XtNselectCallback, XtCCallback, XtRCallback, sizeof(caddr_t),
  246.    XtOffset(OctWidget, oct.select), XtRCallback, NULL}
  247. };
  248.  
  249. OctClassRec octClassRec =
  250. {
  251.   {
  252.     (WidgetClass) &widgetClassRec,    /* superclass */
  253.     "Oct",                /* class name */
  254.     sizeof(OctRec),            /* widget size */
  255.     NULL,                /* class initialize */
  256.     NULL,                /* class part initialize */
  257.     FALSE,                /* class inited */
  258.     InitializeOct,            /* initialize */
  259.     NULL,                /* initialize hook */
  260.     XtInheritRealize,            /* realize */
  261.     actionsListOct,            /* actions */
  262.     XtNumber(actionsListOct),        /* num actions */
  263.     resourcesOct,            /* resources */
  264.     XtNumber(resourcesOct),        /* num resources */
  265.     NULLQUARK,                /* xrm class */
  266.     TRUE,                /* compress motion */
  267.     TRUE,                /* compress exposure */
  268.     TRUE,                /* compress enterleave */
  269.     TRUE,                /* visible interest */
  270.     DestroyOct,                /* destroy */
  271.     ResizeOct,                /* resize */
  272.     ExposeOct,                /* expose */
  273.     SetValuesOct,            /* set values */
  274.     NULL,                /* set values hook */
  275.     XtInheritSetValuesAlmost,        /* set values almost */
  276.     NULL,                /* get values hook */
  277.     NULL,                /* accept focus */
  278.     XtVersion,                /* version */
  279.     NULL,                /* callback private */
  280.     defaultTranslationsOct,        /* tm table */
  281.     NULL,                /* query geometry */
  282.     NULL,                /* display accelerator */
  283.     NULL                /* extension */
  284.   },
  285.   {
  286.     0                    /* ignore */
  287.   }
  288. };
  289.  
  290. WidgetClass octWidgetClass = (WidgetClass) &octClassRec;
  291.  
  292. typedef struct _RowNextP3
  293. {
  294.   int viewChanged, face, direction;
  295. } RowNextP3;
  296. static OctLoc rowToRotate[MAXFACES][COORD] = 
  297. {
  298.   {{IGNORE, IGNORE}, {1,     CW}, {2,     CW}, {3,     CW},
  299.    {IGNORE, IGNORE}, {1,    CCW}, {2,    CCW}, {3,    CCW}},
  300.  
  301.   {{3,    CCW}, {0,    CCW}, {IGNORE, IGNORE}, {2,     CW},
  302.    {3,     CW}, {0,     CW}, {IGNORE, IGNORE}, {2,    CCW}},
  303.  
  304.   {{IGNORE, IGNORE}, {3,    CCW}, {0,    CCW}, {1,    CCW},
  305.    {IGNORE, IGNORE}, {3,     CW}, {0,     CW}, {1,     CW}},
  306.  
  307.   {{1,     CW}, {2,     CW}, {IGNORE, IGNORE}, {0,    CCW},
  308.    {1,    CCW}, {2,    CCW}, {IGNORE, IGNORE}, {0,     CW}},
  309.  
  310.   {{IGNORE, IGNORE}, {3,    CCW}, {2,    CCW}, {1,    CCW},
  311.    {IGNORE, IGNORE}, {3,     CW}, {2,     CW}, {1,     CW}},
  312.  
  313.   {{1,     CW}, {0,     CW}, {IGNORE, IGNORE}, {2,    CCW},
  314.    {1,    CCW}, {0,    CCW}, {IGNORE, IGNORE}, {2,     CW}},
  315.  
  316.   {{IGNORE, IGNORE}, {1,     CW}, {0,     CW}, {3,     CW},
  317.    {IGNORE, IGNORE}, {1,    CCW}, {0,    CCW}, {3,    CCW}},
  318.  
  319.   {{3,    CCW}, {2,    CCW}, {IGNORE, IGNORE}, {0,     CW},
  320.    {3,     CW}, {2,     CW}, {IGNORE, IGNORE}, {0,    CCW}}
  321. };
  322. static RowNextP3 slideNextRowP3[MAXSIDES][COORD] =
  323. {
  324.   {
  325.     {IGNORE, IGNORE, IGNORE},
  326.     {  TRUE,      2,     TR},
  327.     { FALSE,      1,     BR},
  328.     { FALSE,      1, BOTTOM},
  329.     {IGNORE, IGNORE, IGNORE},
  330.     { FALSE,      3, BOTTOM},
  331.     { FALSE,      3,     BL},
  332.     {  TRUE,      2,     TL}
  333.   },
  334.   {
  335.     { FALSE,      0,     TL},
  336.     {  TRUE,      1,     BL},
  337.     {IGNORE, IGNORE, IGNORE},
  338.     {  TRUE,      1,     TL},
  339.     { FALSE,      2,     BL},
  340.     { FALSE,      2,   LEFT},
  341.     {IGNORE, IGNORE, IGNORE},
  342.     { FALSE,      0,   LEFT}
  343.   },
  344.   {
  345.     {IGNORE, IGNORE, IGNORE},
  346.     { FALSE,      1,    TOP},
  347.     { FALSE,      1,     TR},
  348.     {  TRUE,      0,     BR},
  349.     {IGNORE, IGNORE, IGNORE},
  350.     {  TRUE,      0,     BL},
  351.     { FALSE,      3,     TL},
  352.     { FALSE,      3,    TOP},
  353.   },
  354.   {
  355.     { FALSE,      0,     TR},
  356.     { FALSE,      0,  RIGHT},
  357.     {IGNORE, IGNORE, IGNORE},
  358.     { FALSE,      2,  RIGHT},
  359.     { FALSE,      2,     BR},
  360.     {  TRUE,      3,     TR},
  361.     {IGNORE, IGNORE, IGNORE},
  362.     {  TRUE,      3,     BR}
  363.   }
  364. };
  365. static int reverseP3[MAXSIDES][COORD] =
  366. {
  367.   {IGNORE, FALSE,  FALSE,  TRUE, IGNORE,  TRUE,   TRUE,  TRUE},
  368.   {  TRUE,  TRUE, IGNORE, FALSE,  FALSE,  TRUE, IGNORE,  TRUE},
  369.   {IGNORE,  TRUE,   TRUE,  TRUE, IGNORE, FALSE,  FALSE,  TRUE},
  370.   { FALSE,  TRUE, IGNORE,  TRUE,   TRUE,  TRUE, IGNORE, FALSE}
  371. };
  372. static int rotateOrientP3[MAXSIDES][COORD] =
  373. {
  374.   {IGNORE, 11,      7,  2, IGNORE, 10,      5,  1},
  375.   {    11,  7, IGNORE,  5,      1,  2, IGNORE, 10},
  376.   {IGNORE, 10,      5,  1, IGNORE, 11,      7,  2},
  377.   {     1,  2, IGNORE, 10,     11,  7, IGNORE,  5}
  378. };
  379.  
  380. static XPoint triangleUnit[MAXSIDES][4] =
  381. {
  382.   {{0, 0}, { 1,  1}, {-2,  0}, { 1, -1}},
  383.   {{0, 0}, {-1,  1}, { 0, -2}, { 1,  1}},
  384.   {{0, 0}, {-1, -1}, { 2,  0}, {-1,  1}},
  385.   {{0, 0}, { 1, -1}, { 0,  2}, {-1, -1}}
  386. };
  387. static XPoint triangleList[MAXSIDES][4], letterList[MAXSIDES];
  388.  
  389. static void InitializeOct(request, new)
  390.   Widget request, new;
  391. {
  392.   OctWidget w = (OctWidget) new;
  393.   XGCValues values;
  394.   XtGCMask valueMask;
  395.   int face, orient;
  396.  
  397.   for (face = 0; face < MAXFACES; face++)
  398.     w->oct.octaLoc[face] = NULL;
  399.   for (orient = 0; orient < MAXORIENT / 2; orient++)
  400.     w->oct.rowLoc[orient] = NULL;
  401.   w->oct.faceLoc = NULL;
  402.   CheckPolyhedrons(w);
  403.   InitMoves();
  404.   ResetPolyhedrons(w);
  405.   (void) SRAND(getpid());
  406.   valueMask = GCForeground | GCBackground;
  407.   values.background = w->core.background_pixel;
  408.   values.foreground = w->oct.foreground;
  409.   w->oct.puzzleGC = XtGetGC(new, valueMask, &values);
  410.   values.foreground = w->oct.borderColor;
  411.   w->oct.borderGC = XtGetGC(new, valueMask, &values);
  412.   w->oct.depth = DefaultDepthOfScreen(XtScreen(w));
  413.   valueMask = GCForeground | GCBackground;
  414.   values.foreground = w->core.background_pixel;
  415.   values.background = w->oct.foreground;
  416.   w->oct.inverseGC = XtGetGC(new, valueMask, &values);
  417.   for (face = 0; face < MAXFACES; face++)
  418.     GetColor(w, face, TRUE);
  419.   ResizeOct(w);
  420. }
  421.  
  422. static void DestroyOct(old)
  423.   Widget old;
  424. {
  425.   OctWidget w = (OctWidget) old;
  426.   int face;
  427.  
  428.   for (face = 0; face < MAXFACES; face++)
  429.     XtReleaseGC(old, w->oct.faceGC[face]);
  430.   XtReleaseGC(old, w->oct.borderGC);
  431.   XtReleaseGC(old, w->oct.puzzleGC);
  432.   XtReleaseGC(old, w->oct.inverseGC);
  433.   XtRemoveCallbacks(old, XtNselectCallback, w->oct.select);
  434. }
  435.  
  436. static void ResizeOct(w)
  437.   OctWidget w;
  438. {
  439.   int tempLength;
  440.  
  441.   w->oct.delta = 4;
  442.   w->oct.vertical = (w->core.height >= w->core.width);
  443.   if (w->oct.vertical)
  444.     tempLength = MIN(w->core.height / 2, w->core.width);
  445.   else
  446.     tempLength = MIN(w->core.height, w->core.width / 2);
  447.   w->oct.octaLength = MAX((tempLength - w->oct.delta + 1) / w->oct.size, 0);
  448.   w->oct.faceLength = w->oct.size * w->oct.octaLength;
  449.   w->oct.viewLength = w->oct.faceLength + w->oct.delta + 3;
  450.   w->oct.viewMiddle = w->oct.viewLength / 2;
  451.   if (w->oct.vertical) {
  452.     w->oct.puzzleSize.x = w->oct.viewLength - 1;
  453.     w->oct.puzzleSize.y = 2 * w->oct.viewLength - w->oct.delta - 2;
  454.   } else {
  455.     w->oct.puzzleSize.x = 2 * w->oct.viewLength - w->oct.delta - 2;
  456.     w->oct.puzzleSize.y = w->oct.viewLength - 1;
  457.   }
  458.   w->oct.puzzleOffset.x = ((int) w->core.width - w->oct.puzzleSize.x) / 2;
  459.   w->oct.puzzleOffset.y = ((int) w->core.height - w->oct.puzzleSize.y) / 2;
  460.   ResizePolyhedrons(w);
  461. }
  462.  
  463. static void ExposeOct(new, event, region)
  464.   Widget new;
  465.   XEvent *event;
  466.   Region region; /* Not used */
  467. {
  468.   OctWidget w = (OctWidget) new;
  469.  
  470.   if (w->core.visible) {
  471.     DrawFrame(w, w->oct.puzzleGC);
  472.     DrawAllPolyhedrons(w);
  473.   }
  474. }
  475.  
  476. static Boolean SetValuesOct(current, request, new)
  477.   Widget current, request, new;
  478. {
  479.   OctWidget c = (OctWidget) current, w = (OctWidget) new;
  480.   XGCValues values;
  481.   XtGCMask valueMask;
  482.   Boolean redraw = FALSE;
  483.   int face;
  484.  
  485.   CheckPolyhedrons(w);
  486.   if (w->oct.foreground != c->oct.foreground) {
  487.     valueMask = GCForeground | GCBackground;
  488.     values.foreground = w->oct.foreground;
  489.     values.background = w->core.background_pixel;
  490.     XtReleaseGC(new, w->oct.puzzleGC);
  491.     w->oct.puzzleGC = XtGetGC(new, valueMask, &values);
  492.     redraw = TRUE;
  493.   }
  494.   if (w->core.background_pixel != c->core.background_pixel) {
  495.     valueMask = GCForeground | GCBackground;
  496.     values.foreground = w->core.background_pixel;
  497.     values.background = w->oct.foreground;
  498.     XtReleaseGC(new, w->oct.inverseGC);
  499.     w->oct.inverseGC = XtGetGC(new, valueMask, &values);
  500.     redraw = TRUE;
  501.   }
  502.   if (w->oct.borderColor != c->oct.borderColor) {
  503.     valueMask = GCForeground | GCBackground;
  504.     values.foreground = w->oct.borderColor;
  505.     values.background = w->core.background_pixel;
  506.     XtReleaseGC(new, w->oct.borderGC);
  507.     w->oct.borderGC = XtGetGC(new, valueMask, &values);
  508.     redraw = TRUE;
  509.   }
  510.   if (w->oct.mono || w->oct.depth == 1) {
  511.     valueMask = GCForeground | GCBackground;
  512.     values.background = w->core.background_pixel;
  513.     values.foreground = w->oct.foreground;
  514.     for (face = 0; face < MAXFACES; face++) {
  515.       XtReleaseGC(new, w->oct.faceGC[face]);
  516.       w->oct.faceGC[face] = XtGetGC(new, valueMask, &values);
  517.     }
  518.     redraw = TRUE;
  519.   }
  520.   for (face = 0; face < MAXFACES; face++) {
  521.     if (strcmp(w->oct.faceName[face], c->oct.faceName[face]))
  522.       GetColor(w, face, FALSE);
  523.   }
  524.   if (w->oct.orient != c->oct.orient) {
  525.     ResetPolyhedrons(w);
  526.     redraw = TRUE;
  527.   } else if (w->oct.practice != c->oct.practice) {
  528.     ResetPolyhedrons(w);
  529.     redraw = TRUE;
  530.   }
  531.   if (w->oct.size != c->oct.size ||
  532.       w->oct.mode != c->oct.mode ||
  533.       w->oct.sticky != c->oct.sticky) {
  534.     ResetPolyhedrons(w);
  535.     ResizeOct(w);
  536.     redraw = TRUE;
  537.   }
  538.   if (w->oct.octaLength != c->oct.octaLength) {
  539.     ResizeOct(w);
  540.     redraw = TRUE;
  541.   }
  542.   return (redraw);
  543. }
  544.  
  545. static void QuitOct(w, event, args, nArgs)
  546.   OctWidget w;
  547.   XEvent *event;
  548.   char *args[];
  549.   int nArgs;
  550. {
  551.   XtCloseDisplay(XtDisplay(w));
  552.   exit(0);
  553. }
  554.  
  555. static void SelectOct(w, event, args, nArgs)
  556.   OctWidget w;
  557.   XEvent *event;
  558.   char *args[];
  559.   int nArgs;
  560. {
  561.   int control;
  562.   RTT rtt;
  563.  
  564.   if (SelectPolyhedrons(w, event->xbutton.x, event->xbutton.y,
  565.              &(w->oct.currentFace), &rtt)) {
  566.     control = (int) (event->xkey.state & ControlMask);
  567.     if (control || w->oct.practice || !CheckSolved(w)) {
  568.       w->oct.currentPosition = ToPosition(rtt);
  569.       DrawTriangle(w, w->oct.currentFace, w->oct.currentPosition, TRUE);
  570.     }
  571.   } else
  572.     w->oct.currentFace = -1;
  573. }
  574.  
  575. static void ReleaseOct(w, event, args, nArgs)
  576.   OctWidget w;
  577.   XEvent *event;
  578.   char *args[];
  579.   int nArgs;
  580. {
  581.   int shift, control, style, face, count = -1, direction = 0;
  582.   RTT rtt;
  583.   octCallbackStruct cb;
  584.  
  585.   if (w->oct.currentFace == -1)
  586.     return;
  587.       DrawTriangle(w, w->oct.currentFace, w->oct.currentPosition, FALSE);
  588.   shift = (int) (event->xbutton.state & (ShiftMask | LockMask));
  589.   control = (int) (event->xkey.state & ControlMask);
  590.   if (!control && !w->oct.practice && CheckSolved(w))
  591.     MoveNoPolyhedrons(w);
  592.   else if (SelectPolyhedrons(w, event->xbutton.x, event->xbutton.y,
  593.              &face, &rtt)) {
  594.     control = (control) ? 1 : 0;
  595.     if (w->oct.mode != BOTH) {
  596.       if (control && shift)
  597.         style = (w->oct.mode == PERIOD4) ? PERIOD3 : PERIOD4;
  598.       else
  599.         style = (w->oct.mode == PERIOD3) ? PERIOD3 : PERIOD4;
  600.     } else
  601.       style = (shift) ? PERIOD4 : PERIOD3;
  602.     if (face == w->oct.currentFace)
  603.       count = CheckMoveDir(w, ToRTT(w->oct.currentPosition), rtt, face,
  604.                 &direction);
  605.     if (count == 1 && NarrowSelection(w, style, &face, &direction)) {
  606.       MoveOct(w, face, w->oct.currentPosition, direction, style, control);
  607.       if (!control && CheckSolved(w)) {
  608.         cb.reason = OCT_SOLVED;
  609.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  610.       }
  611.     } else if (count == 2) {
  612.       cb.reason = OCT_AMBIGUOUS;
  613.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  614.     } else if (!count)
  615.       MoveNoPolyhedrons(w);
  616.   }
  617. }
  618.  
  619. static void PracticeOct(w, event, args, nArgs)
  620.   OctWidget w;
  621.   XEvent *event;
  622.   char *args[];
  623.   int nArgs;
  624. {
  625.   PracticePolyhedrons(w);
  626. }
  627.  
  628. static void PracticeOctMaybe(w, event, args, nArgs)
  629.   OctWidget w;
  630.   XEvent *event;
  631.   char *args[];
  632.   int nArgs;
  633. {
  634.   if (!w->oct.started)
  635.     PracticePolyhedrons(w);
  636. }
  637.  
  638. static void RandomizeOct(w, event, args, nArgs)
  639.   OctWidget w;
  640.   XEvent *event;
  641.   char *args[];
  642.   int nArgs;
  643. {
  644.   RandomizePolyhedrons(w);
  645. }
  646.  
  647. static void RandomizeOctMaybe(w, event, args, nArgs)
  648.   OctWidget w;
  649.   XEvent *event;
  650.   char *args[];
  651.   int nArgs;
  652. {
  653.   if (!w->oct.started)
  654.     RandomizePolyhedrons(w);
  655. }
  656.  
  657. static void GetOct(w, event, args, nArgs)
  658.   OctWidget w;
  659.   XEvent *event;
  660.   char *args[];
  661.   int nArgs;
  662. {
  663.   FILE *fp;
  664.   char c;
  665.   int i, size, mode, sticky, orient, practice, moves;
  666.   octCallbackStruct cb;
  667.  
  668.   if ((fp = fopen(DATAFILE, "r")) == NULL)
  669.     (void) printf("Can not read %s to enter.\n", DATAFILE);
  670.   else {
  671.     FlushMoves(w);
  672.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  673.     (void) fscanf(fp, "%d", &size);
  674.     if (size >= MINOCTAS) {
  675.       for (i = w->oct.size; i < size; i++) {
  676.         cb.reason = OCT_INC;
  677.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  678.       }
  679.       for (i = w->oct.size; i > size; i--) {
  680.         cb.reason = OCT_DEC;
  681.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  682.       }
  683.     } else
  684.       (void) printf("%s corrupted: size %d should be between %d and MAXINT\n",
  685.          DATAFILE, size, MINOCTAS);
  686.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  687.     (void) fscanf(fp, "%d", &mode);
  688.     if (mode >= PERIOD3 && mode <= BOTH)
  689.       switch (mode) {
  690.         case PERIOD3:
  691.           cb.reason = OCT_PERIOD3;
  692.           XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  693.           break;
  694.         case PERIOD4:
  695.           cb.reason = OCT_PERIOD4;
  696.           XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  697.           break;
  698.         case BOTH:
  699.           cb.reason = OCT_BOTH;
  700.           XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  701.       }
  702.     else
  703.       (void) printf("%s corrupted: mode %d should be between %d and %d\n",
  704.          DATAFILE, mode, PERIOD3, BOTH);
  705.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  706.     (void) fscanf(fp, "%d", &sticky);
  707.     if (w->oct.sticky != (Boolean) sticky) {
  708.       cb.reason = OCT_STICKY;
  709.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  710.     }
  711.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  712.     (void) fscanf(fp, "%d", &orient);
  713.     if (w->oct.orient != (Boolean) orient) {
  714.       cb.reason = OCT_ORIENT;
  715.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  716.     }
  717.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  718.     (void) fscanf(fp, "%d", &practice);
  719.     if (w->oct.practice != (Boolean) practice) {
  720.       cb.reason = OCT_PRACTICE;
  721.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  722.     }
  723.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  724.     (void) fscanf(fp, "%d", &moves);
  725.     ScanStartPosition(fp, w);
  726.     cb.reason = OCT_RESTORE;
  727.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  728.     SetStartPosition(w);
  729.     ScanMoves(fp, w, moves);
  730.     (void) fclose(fp);
  731.     (void) printf("%s: size %d, mode %d, sticky %d, orient %d",
  732.       DATAFILE, size, mode, sticky, orient);
  733.     (void) printf(", practice %d, moves %d.\n", practice, moves);
  734.   }
  735. }
  736.  
  737. static void WriteOct(w, event, args, nArgs)
  738.   OctWidget w;
  739.   XEvent *event;
  740.   char *args[];
  741.   int nArgs;
  742. {
  743.   FILE *fp;
  744.  
  745.   if ((fp = fopen(DATAFILE, "w")) == NULL)
  746.     (void) printf("Can not write to %s.\n", DATAFILE);
  747.   else {
  748.     (void) fprintf(fp, "size%c %d\n", SYMBOL, w->oct.size);
  749.     (void) fprintf(fp, "mode%c %d\n", SYMBOL, w->oct.mode);
  750.     (void) fprintf(fp, "sticky%c %d\n", SYMBOL, (w->oct.sticky) ? 1 : 0);
  751.     (void) fprintf(fp, "orient%c %d\n", SYMBOL, (w->oct.orient) ? 1 : 0);
  752.     (void) fprintf(fp, "practice%c %d\n", SYMBOL, (w->oct.practice) ? 1 : 0);
  753.     (void) fprintf(fp, "moves%c %d\n", SYMBOL, NumMoves());
  754.     PrintStartPosition(fp, w);
  755.     PrintMoves(fp);
  756.     (void) fclose(fp);
  757.     (void) printf("Saved to %s.\n", DATAFILE);
  758.   }
  759. }
  760.  
  761. static void UndoOct(w, event, args, nArgs)
  762.   OctWidget w;
  763.   XEvent *event;
  764.   char *args[];
  765.   int nArgs;
  766. {
  767.   if (MadeMoves()) {
  768.     int face, position, direction, style, control;
  769.  
  770.     GetMove(&face, &position, &direction, &style, &control);
  771.     direction = (direction < COORD) ?
  772.       (direction + MAXSIDES) % MAXFACES : 3 * COORD - direction;
  773.     if (control)
  774.       MoveControlCb(w, face, direction, style);
  775.     else {
  776.       octCallbackStruct cb;
  777.  
  778.       MovePolyhedrons(w, face, ToRTT(position), direction, style);
  779.       cb.reason = OCT_UNDO;
  780.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  781.     }
  782.   }
  783. }
  784.  
  785. static void SolveOct(w, event, args, nArgs)
  786.   OctWidget w;
  787.   XEvent *event;
  788.   char *args[];
  789.   int nArgs;
  790. {
  791.   /* SolvePolyhedrons(w); */ /* Sorry, unimplemented */
  792. }
  793.  
  794. static void IncrementOct(w, event, args, nArgs)
  795.   OctWidget w;
  796.   XEvent *event;
  797.   char *args[];
  798.   int nArgs;
  799. {
  800.   octCallbackStruct cb;
  801.  
  802.   cb.reason = OCT_INC;
  803.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  804. }
  805.  
  806. static void DecrementOct(w, event, args, nArgs)
  807.   OctWidget w;
  808.   XEvent *event;
  809.   char *args[];
  810.   int nArgs;
  811. {
  812.   octCallbackStruct cb;
  813.  
  814.   if (w->oct.size <= MINOCTAS)
  815.     return;
  816.   cb.reason = OCT_DEC;
  817.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  818. }
  819.  
  820. static void OrientizeOct(w, event, args, nArgs)
  821.   OctWidget w;
  822.   XEvent *event;
  823.   char *args[];
  824.   int nArgs;
  825. {
  826.   octCallbackStruct cb;
  827.  
  828.   cb.reason = OCT_ORIENT;
  829.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  830. }
  831.  
  832. static void Period3ModeOct(w, event, args, nArgs)
  833.   OctWidget w;
  834.   XEvent *event;
  835.   char *args[];
  836.   int nArgs;
  837. {
  838.   octCallbackStruct cb;
  839.  
  840.   cb.reason = OCT_PERIOD3;
  841.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  842. }
  843.  
  844. static void Period4ModeOct(w, event, args, nArgs)
  845.   OctWidget w;
  846.   XEvent *event;
  847.   char *args[];
  848.   int nArgs;
  849. {
  850.   octCallbackStruct cb;
  851.  
  852.   cb.reason = OCT_PERIOD4;
  853.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  854. }
  855.  
  856. static void BothModeOct(w, event, args, nArgs)
  857.   OctWidget w;
  858.   XEvent *event;
  859.   char *args[];
  860.   int nArgs;
  861. {
  862.   octCallbackStruct cb;
  863.  
  864.   cb.reason = OCT_BOTH;
  865.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  866. }
  867.  
  868. static void StickyModeOct(w, event, args, nArgs)
  869.   OctWidget w;
  870.   XEvent *event;
  871.   char *args[];
  872.   int nArgs;
  873. {
  874.   octCallbackStruct cb;
  875.  
  876.   cb.reason = OCT_STICKY;
  877.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  878. }
  879.  
  880. static void MoveOctCcw(w, event, args, nArgs)
  881.   OctWidget w;
  882.   XEvent *event;
  883.   char *args[];
  884.   int nArgs;
  885. {
  886.   MoveOctInput(w, event->xbutton.x, event->xbutton.y, CCW,
  887.     (int) (event->xbutton.state & (ShiftMask | LockMask)),
  888.     (int) (event->xbutton.state & ControlMask));
  889. }
  890.  
  891. static void MoveOctTl(w, event, args, nArgs)
  892.   OctWidget w;
  893.   XEvent *event;
  894.   char *args[];
  895.   int nArgs;
  896. {
  897.   MoveOctInput(w, event->xbutton.x, event->xbutton.y, TL,
  898.     (int) (event->xbutton.state & (ShiftMask | LockMask)),
  899.     (int) (event->xkey.state & ControlMask));
  900. }
  901.  
  902. static void MoveOctTop(w, event, args, nArgs)
  903.   OctWidget w;
  904.   XEvent *event;
  905.   char *args[];
  906.   int nArgs;
  907. {
  908.   MoveOctInput(w, event->xbutton.x, event->xbutton.y, TOP,
  909.     (int) (event->xbutton.state & (ShiftMask | LockMask)),
  910.     (int) (event->xkey.state & ControlMask));
  911. }
  912.  
  913. static void MoveOctTr(w, event, args, nArgs)
  914.   OctWidget w;
  915.   XEvent *event;
  916.   char *args[];
  917.   int nArgs;
  918. {
  919.   MoveOctInput(w, event->xbutton.x, event->xbutton.y, TR,
  920.     (int) (event->xbutton.state & (ShiftMask | LockMask)),
  921.     (int) (event->xkey.state & ControlMask));
  922. }
  923.  
  924. static void MoveOctLeft(w, event, args, nArgs)
  925.   OctWidget w;
  926.   XEvent *event;
  927.   char *args[];
  928.   int nArgs;
  929. {
  930.   MoveOctInput(w, event->xbutton.x, event->xbutton.y, LEFT,
  931.     (int) (event->xbutton.state & (ShiftMask | LockMask)),
  932.     (int) (event->xkey.state & ControlMask));
  933. }
  934.  
  935. static void MoveOctCw(w, event, args, nArgs)
  936.   OctWidget w;
  937.   XEvent *event;
  938.   char *args[];
  939.   int nArgs;
  940. {
  941.   MoveOctInput(w, event->xbutton.x, event->xbutton.y, CW,
  942.     (int) (event->xbutton.state & (ShiftMask | LockMask)),
  943.     (int) (event->xkey.state & ControlMask));
  944. }
  945.  
  946. static void MoveOctRight(w, event, args, nArgs)
  947.   OctWidget w;
  948.   XEvent *event;
  949.   char *args[];
  950.   int nArgs;
  951. {
  952.   MoveOctInput(w, event->xbutton.x, event->xbutton.y, RIGHT,
  953.     (int) (event->xbutton.state & (ShiftMask | LockMask)),
  954.     (int) (event->xkey.state & ControlMask));
  955. }
  956.  
  957. static void MoveOctBl(w, event, args, nArgs)
  958.   OctWidget w;
  959.   XEvent *event;
  960.   char *args[];
  961.   int nArgs;
  962. {
  963.   MoveOctInput(w, event->xbutton.x, event->xbutton.y, BL,
  964.     (int) (event->xbutton.state & (ShiftMask | LockMask)),
  965.     (int) (event->xkey.state & ControlMask));
  966. }
  967.  
  968. static void MoveOctBottom(w, event, args, nArgs)
  969.   OctWidget w;
  970.   XEvent *event;
  971.   char *args[];
  972.   int nArgs;
  973. {
  974.   MoveOctInput(w, event->xbutton.x, event->xbutton.y, BOTTOM,
  975.     (int) (event->xbutton.state & (ShiftMask | LockMask)),
  976.     (int) (event->xkey.state & ControlMask));
  977. }
  978.  
  979. static void MoveOctBr(w, event, args, nArgs)
  980.   OctWidget w;
  981.   XEvent *event;
  982.   char *args[];
  983.   int nArgs;
  984. {
  985.   MoveOctInput(w, event->xbutton.x, event->xbutton.y, BR,
  986.     (int) (event->xbutton.state & (ShiftMask | LockMask)),
  987.     (int) (event->xkey.state & ControlMask));
  988. }
  989.  
  990. static void MoveOctInput(w, x, y, direction, shift, control)
  991.   OctWidget w;
  992.   int x, y, direction, shift, control;
  993. {
  994.   int style, face;
  995.   RTT rtt;
  996.  
  997.   if (w->oct.mode != BOTH) {
  998.     if (control && shift)
  999.       style = (w->oct.mode == PERIOD4) ? PERIOD3 : PERIOD4;
  1000.     else
  1001.       style = (w->oct.mode == PERIOD3) ? PERIOD3 : PERIOD4;
  1002.   } else
  1003.     style = (shift) ? PERIOD4 : PERIOD3;
  1004.   if (!w->oct.practice && !control && CheckSolved(w)) {
  1005.     MoveNoPolyhedrons(w);
  1006.     return;
  1007.   }
  1008.   if (!PositionPolyhedrons(w, x, y, style, &face, &rtt, &direction))
  1009.     return;
  1010.   control = (control) ? 1 : 0;
  1011.   MoveOct(w, face, ToPosition(rtt), direction, style, control);
  1012.   if (!control && CheckSolved(w)) {
  1013.     octCallbackStruct cb;
  1014.  
  1015.     cb.reason = OCT_SOLVED;
  1016.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1017.   }
  1018. }
  1019.  
  1020. void MoveOct(w, face, position, direction, style, control)
  1021.   OctWidget w;
  1022.   int face, position, direction, style, control;
  1023. {
  1024.   if (control)
  1025.     MoveControlCb(w, face, direction, style);
  1026.   else {
  1027.     octCallbackStruct cb;
  1028.  
  1029.     MovePolyhedrons(w, face, ToRTT(position), direction, style);
  1030.     cb.reason = OCT_MOVED;
  1031.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1032.   }
  1033.   PutMove(face, position, direction, style, control);
  1034. }
  1035.  
  1036. static void GetColor(w, face, init)
  1037.   OctWidget w;
  1038.   int face, init;
  1039. {
  1040.   XGCValues values;
  1041.   XtGCMask valueMask;
  1042.   XColor colorCell, rgb;
  1043.  
  1044.   valueMask = GCForeground | GCBackground;
  1045.   values.background = w->core.background_pixel;
  1046.   if (w->oct.depth > 1 && !w->oct.mono) {
  1047.     if (XAllocNamedColor(XtDisplay(w),
  1048.         DefaultColormap(XtDisplay(w), XtWindow(w)),
  1049.         w->oct.faceName[face], &colorCell, &rgb)) {
  1050.       values.foreground = w->oct.faceColor[face] = colorCell.pixel;
  1051.       if (!init)
  1052.         XtReleaseGC((Widget) w, w->oct.faceGC[face]);
  1053.       w->oct.faceGC[face] = XtGetGC((Widget) w, valueMask, &values);
  1054.       return;
  1055.     } else {
  1056.       char buf[121];
  1057.  
  1058.       (void) sprintf(buf, "Color name \"%s\" is not defined",
  1059.                w->oct.faceName[face]);
  1060.       XtWarning(buf);
  1061.     }
  1062.   }
  1063.   values.foreground = w->oct.foreground;
  1064.   if (!init)
  1065.     XtReleaseGC((Widget) w, w->oct.faceGC[face]);
  1066.   w->oct.faceGC[face] = XtGetGC((Widget) w, valueMask, &values);
  1067. }
  1068.  
  1069. static void MoveControlCb(w, face, direction, style)
  1070.   OctWidget w;
  1071.   int face, direction, style;
  1072. {
  1073.   octCallbackStruct cb;
  1074.   int i, j;
  1075.   RTT rtt;
  1076.  
  1077.   if (w->oct.sticky) {
  1078.     if (style == PERIOD3)
  1079.       for (i = 0; i < 3; i++) {
  1080.         if (i == 2)
  1081.           i++;
  1082.         rtt.row = i; rtt.trbl = i; rtt.tlbr = i; 
  1083.         MovePolyhedrons(w, face, rtt, direction, style);
  1084.         cb.reason = OCT_CONTROL;
  1085.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1086.       }
  1087.     else /* (style == PERIOD4) */
  1088.       for (i = 0; i < 3; i++) {
  1089.         if (i < 2) {
  1090.           if (i == 1)
  1091.             j = i + 2;
  1092.           else
  1093.             j = i;
  1094.           rtt.row = j; rtt.trbl = j; rtt.tlbr = j; 
  1095.           MovePolyhedrons(w, face, rtt, direction, style);
  1096.         } else {
  1097.           if (direction == CW || direction == CCW) {
  1098.             j = i - 2;
  1099.             rtt.row = j; rtt.trbl = j; rtt.tlbr = j;
  1100.             MovePolyhedrons(w,
  1101.               (!(face / MAXSIDES)) * MAXSIDES + ((face % 2) ?
  1102.                 (face + MAXSIDES / 2) % MAXSIDES : face % MAXSIDES), rtt,
  1103.               (direction == CW) ? CCW : CW, style);
  1104.           } else {
  1105.             j = i + 1;
  1106.             rtt.row = j; rtt.trbl = j; rtt.tlbr = j; 
  1107.             MovePolyhedrons(w,
  1108.               (!(face / MAXSIDES)) * MAXSIDES + ((face % 2) ?
  1109.                 (face + MAXSIDES / 2) % MAXSIDES : face % MAXSIDES), rtt,
  1110.               ((direction / 2) % 2) ? (direction + 2) % MAXFACES :
  1111.                 (direction + 6) % MAXFACES, style);
  1112.           }
  1113.         }
  1114.         cb.reason = OCT_CONTROL;
  1115.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1116.       }
  1117.   } else {
  1118.     if (style == PERIOD3)
  1119.       for (i = 0; i < w->oct.size; i++) {
  1120.         rtt.row = i; rtt.trbl = i; rtt.tlbr = i; 
  1121.         MovePolyhedrons(w, face, rtt, direction, style);
  1122.         cb.reason = OCT_CONTROL;
  1123.           XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1124.       }
  1125.     else /* (style == PERIOD4) */
  1126.       for (i = 0; i < 2 * w->oct.size - 1; i++) {
  1127.         if (i < w->oct.size) {
  1128.           rtt.row = i; rtt.trbl = i; rtt.tlbr = i; 
  1129.           MovePolyhedrons(w, face, rtt, direction, style);
  1130.         } else {
  1131.           if (direction == CW || direction == CCW) {
  1132.             j = i - w->oct.size;
  1133.             rtt.row = j; rtt.trbl = j; rtt.tlbr = j; 
  1134.             MovePolyhedrons(w,
  1135.               (!(face / MAXSIDES)) * MAXSIDES + ((face % 2) ?
  1136.                 (face + MAXSIDES / 2) % MAXSIDES : face % MAXSIDES), rtt,
  1137.               (direction == CW) ? CCW : CW, style);
  1138.           } else {
  1139.             j = i - w->oct.size + 1;
  1140.             rtt.row = j; rtt.trbl = j; rtt.tlbr = j; 
  1141.             MovePolyhedrons(w,
  1142.               (!(face / MAXSIDES)) * MAXSIDES + ((face % 2) ?
  1143.                 (face + MAXSIDES / 2) % MAXSIDES : face % MAXSIDES), rtt,
  1144.               ((direction / 2) % 2) ? (direction + 2) % MAXFACES :
  1145.                 (direction + 6) % MAXFACES, style);
  1146.           }
  1147.         }
  1148.         cb.reason = OCT_CONTROL;
  1149.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1150.       }
  1151.   }
  1152. }
  1153.  
  1154. static void CheckPolyhedrons(w)
  1155.   OctWidget w;
  1156. {
  1157.   if (w->oct.size < MINOCTAS) {
  1158.     char buf[121];
  1159.  
  1160.     (void) sprintf(buf, "Number of Octas on edge out of bounds, use %d..MAXINT",
  1161.              MINOCTAS);
  1162.     XtWarning(buf);
  1163.     w->oct.size = DEFAULTOCTAS;
  1164.   }
  1165.   if (w->oct.mode < PERIOD3 || w->oct.mode > BOTH) {
  1166.     XtWarning("Mode is in error, use 3 for Period3, 4 for Period4, 5 for Both");
  1167.     w->oct.mode = DEFAULTMODE;
  1168.   }
  1169. }
  1170.  
  1171. static void ResetPolyhedrons(w)
  1172.   OctWidget w;
  1173. {
  1174.   int face, position, orient;
  1175.  
  1176.   w->oct.sizeSize = w->oct.size * w->oct.size;
  1177.   for (face = 0; face < MAXFACES; face++) {
  1178.     if (w->oct.octaLoc[face])
  1179.       (void) free((void *) w->oct.octaLoc[face]);
  1180.     if (!(w->oct.octaLoc[face] = (OctLoc *)
  1181.           malloc(sizeof(OctLoc) * w->oct.sizeSize)))
  1182.       XtError("Not enough memory, exiting.");
  1183.     if (startLoc[face])
  1184.       (void) free((void *) startLoc[face]);
  1185.     if (!(startLoc[face] = (OctLoc *)
  1186.           malloc(sizeof(OctLoc) * w->oct.sizeSize)))
  1187.       XtError("Not enough memory, exiting.");
  1188.   }
  1189.   for (orient = 0; orient < MAXORIENT / 2; orient++) {
  1190.     if (w->oct.rowLoc[orient])
  1191.       (void) free((void *) w->oct.rowLoc[orient]);
  1192.     if (!(w->oct.rowLoc[orient] = (OctLoc *)
  1193.           malloc(sizeof(OctLoc) * (2 * w->oct.size - 1))))
  1194.       XtError("Not enough memory, exiting.");
  1195.   }
  1196.   if (w->oct.faceLoc)
  1197.     (void) free((void *) w->oct.faceLoc);
  1198.   if (!(w->oct.faceLoc = (OctLoc *)
  1199.         malloc(sizeof(OctLoc) * w->oct.sizeSize)))
  1200.     XtError("Not enough memory, exiting.");
  1201.   for (face = 0; face < MAXFACES; face++)
  1202.     for (position = 0; position < w->oct.sizeSize; position++) {
  1203.       w->oct.octaLoc[face][position].face = face;
  1204.       w->oct.octaLoc[face][position].rotation = 3 * face % MAXORIENT;
  1205.     }
  1206.   FlushMoves(w);
  1207.   w->oct.started = FALSE;
  1208. }
  1209.  
  1210. static void ResizePolyhedrons(w)
  1211.   OctWidget w;
  1212. {
  1213.   int i, j;
  1214.  
  1215.   w->oct.octaLength = w->oct.faceLength / (2 * w->oct.size) -
  1216.     w->oct.delta - 1;
  1217.   for (i = 0; i <= 3; i++)
  1218.     for (j = 0; j < MAXSIDES; j++) { 
  1219.       triangleList[j][i].x = triangleUnit[j][i].x * w->oct.octaLength;
  1220.       triangleList[j][i].y = triangleUnit[j][i].y * w->oct.octaLength;
  1221.     }
  1222.   letterList[TOP / 2].x = -2;
  1223.   letterList[TOP / 2].y = 3 * w->oct.octaLength / 5 + 3;
  1224.   letterList[RIGHT / 2].x = -3 * w->oct.octaLength / 5 - 4;
  1225.   letterList[RIGHT / 2].y = 3;
  1226.   letterList[BOTTOM / 2].x = -2;
  1227.   letterList[BOTTOM / 2].y = -3 * w->oct.octaLength / 5 + 2;
  1228.   letterList[LEFT / 2].x = 3 * w->oct.octaLength / 5 - 1;
  1229.   letterList[LEFT / 2].y = 3;
  1230.   w->oct.orientLineLength = w->oct.octaLength / 4;
  1231. }
  1232.  
  1233. static int SelectPolyhedrons(w, x, y, face, rtt)
  1234.   OctWidget w;
  1235.   int x, y;
  1236.   int *face;
  1237.   RTT *rtt;
  1238. {
  1239.   int view;
  1240.  
  1241.   x -= w->oct.puzzleOffset.x;
  1242.   y -= w->oct.puzzleOffset.y;
  1243.   if (w->oct.vertical && y > w->oct.viewLength - 1) {
  1244.     y -= (w->oct.viewLength - 1);
  1245.     view = DOWN;
  1246.   } else if (!w->oct.vertical && x > w->oct.viewLength - 1) {
  1247.     x -= (w->oct.viewLength - 1);
  1248.     view = DOWN;
  1249.   } else
  1250.     view = UP;
  1251.   if (x <= 0 || y <= 0 ||
  1252.       x >= w->oct.faceLength + w->oct.delta ||
  1253.       y >= w->oct.faceLength + w->oct.delta)
  1254.     return FALSE;
  1255.   else if (x + y > w->oct.faceLength) {
  1256.     if (x > y)
  1257.       *face = 1;
  1258.     else if (x < y)
  1259.       *face = 2;
  1260.     else
  1261.       return FALSE;
  1262.   } else {
  1263.     if (x > y)
  1264.       *face = 0;
  1265.     else if (x < y)
  1266.       *face = 3;
  1267.     else
  1268.       return FALSE;
  1269.   }
  1270.   rtt->row = 0;
  1271.   while ((x <= (w->oct.size - (rtt->row + 1)) *
  1272.             (w->oct.octaLength + w->oct.delta) ||
  1273.           x >= w->oct.viewMiddle + (rtt->row + 1) *
  1274.             (w->oct.octaLength + w->oct.delta) + 1 ||
  1275.           y <= (w->oct.size - (rtt->row + 1)) *
  1276.             (w->oct.octaLength + w->oct.delta) ||
  1277.           y >= w->oct.viewMiddle + (rtt->row + 1) *
  1278.             (w->oct.octaLength + w->oct.delta) + 1) &&
  1279.          rtt->row < w->oct.size)
  1280.     rtt->row++;
  1281.   rtt->trbl = 0;
  1282.   while ((x + y) / 2 <= (w->oct.size - (rtt->trbl + 1)) *
  1283.            (w->oct.octaLength + w->oct.delta) + 2 * w->oct.delta ||
  1284.          (x + y) / 2 >= w->oct.viewMiddle + (rtt->trbl + 1) *
  1285.            (w->oct.octaLength + w->oct.delta))
  1286.     rtt->trbl++;
  1287.   rtt->tlbr = 0;
  1288.   while (x <= y - 2 * (rtt->tlbr + 1) *
  1289.            (w->oct.octaLength + w->oct.delta) - 2 ||
  1290.          y <= x - 2 * (rtt->tlbr + 1) *
  1291.            (w->oct.octaLength + w->oct.delta) - 2)
  1292.     rtt->tlbr++;
  1293.   if (!w->oct.vertical && view == DOWN)
  1294.     *face = (*face + MAXSIDES / 2) % MAXSIDES;
  1295.   *face += MAXSIDES * view;
  1296.   if (*face % 2) {
  1297.     view = rtt->tlbr;
  1298.     rtt->tlbr = rtt->trbl;
  1299.     rtt->trbl = view;
  1300.   } 
  1301.   return TRUE;
  1302. }
  1303.  
  1304. static int NarrowSelection(w, style, face, direction)
  1305.   OctWidget w;
  1306.   int style;
  1307.   int *face;
  1308.   int *direction;
  1309. {
  1310.   int side, view;
  1311.  
  1312.   side = *face % MAXSIDES;
  1313.   view = *face / MAXSIDES;
  1314.   if (!w->oct.vertical && view == DOWN)
  1315.     *direction = (*direction + MAXSIDES) % MAXFACES;
  1316.   if (!(*direction % 2) && !((*direction / 2 + side) % 2))
  1317.     return FALSE;
  1318.   if (style == PERIOD4) {
  1319.     if (!(*direction % 2)) {
  1320.       if (*direction == (2 * side + 2) % MAXFACES)
  1321.         *direction = CW;
  1322.       else /* *direction == (2 * side + 6) % MAXFACES */
  1323.         *direction = CCW;
  1324.     }
  1325. /*    if (*direction > TL)
  1326.       h = rtt->row;
  1327.     else if (!((*direction / 2) % 2))
  1328.       h = rtt->trbl;
  1329.     else *//* (*direction / 2) % 2 == 1 *//*
  1330.       h = rtt->tlbr;*/
  1331.   }
  1332.   return TRUE;
  1333. }
  1334.  
  1335. static int PositionPolyhedrons(w, x, y, style,
  1336.                                face, rtt, direction)
  1337.   OctWidget w;
  1338.   int x, y, style;
  1339.   int *face;
  1340.   RTT *rtt;
  1341.   int *direction;
  1342. {
  1343.   if (!SelectPolyhedrons(w, x, y, face, rtt))
  1344.     return FALSE;
  1345.   return NarrowSelection(w, style, face, direction);
  1346. }
  1347.  
  1348. static void MoveNoPolyhedrons(w)
  1349.   OctWidget w;
  1350. {
  1351.   octCallbackStruct cb;
  1352.  
  1353.   cb.reason = OCT_ILLEGAL;
  1354.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1355. }
  1356.  
  1357. static void PracticePolyhedrons(w)
  1358.   OctWidget w;
  1359. {
  1360.   octCallbackStruct cb;
  1361.  
  1362.   cb.reason = OCT_PRACTICE;
  1363.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1364. }
  1365.  
  1366. static void RandomizePolyhedrons(w)
  1367.   OctWidget w;
  1368. {
  1369.   octCallbackStruct cb;
  1370.   int randomDirection, face, position, style;
  1371.   int big = w->oct.sizeSize * 3 + NRAND(2);
  1372.  
  1373.   if (big > 1000)
  1374.     big = 1000;
  1375.   if (w->oct.practice)
  1376.     PracticePolyhedrons(w);
  1377.   if (w->oct.sticky)
  1378.     big /= 3;
  1379.   cb.reason = OCT_RESET;
  1380.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1381.  
  1382. #ifdef DEBUG
  1383.   big = 3;
  1384. #endif
  1385.  
  1386.   while (big--) {
  1387.     face = NRAND(MAXFACES);
  1388.     if (w->oct.mode == BOTH)
  1389.       style = NRAND(MAXMODES - 1) + PERIOD3;
  1390.     else
  1391.       style = w->oct.mode;
  1392.     if (w->oct.sticky) {
  1393.       if (style == PERIOD3) {
  1394.         position = 6;
  1395.         randomDirection = NRAND(6);
  1396.         if (randomDirection >= MAXSIDES) {
  1397.           if (randomDirection == 4)
  1398.             randomDirection = CW;
  1399.           else if (randomDirection == 5)
  1400.             randomDirection = CCW;
  1401.         } else
  1402.           randomDirection = randomDirection * 2 + 1;
  1403.       } else /* style == PERIOD4 */ {
  1404.         if (NRAND(2)) /* a point */
  1405.           position = 9;
  1406.         else /* the center */
  1407.           position = 6;
  1408.         randomDirection = NRAND(6);
  1409.         if (randomDirection == 4)
  1410.           randomDirection = CW;
  1411.         else if (randomDirection == 5)
  1412.           randomDirection = CCW;
  1413.         else {
  1414.           randomDirection = randomDirection * 2 + 1;
  1415.           position = 0;
  1416.         }
  1417.       }
  1418.     } else /* (!w->oct.sticky) */ {
  1419.       if (style == PERIOD3) {
  1420.         randomDirection = NRAND(MAXORIENT / 2);
  1421.         if (randomDirection >= MAXSIDES) {
  1422.           if (randomDirection == 4)
  1423.             if (face % 2)
  1424.               randomDirection = BOTTOM;
  1425.             else
  1426.               randomDirection = RIGHT;
  1427.           else if (randomDirection == 5)
  1428.             if (face % 2)
  1429.               randomDirection = TOP;
  1430.             else
  1431.               randomDirection = LEFT;
  1432.         } else
  1433.           randomDirection = randomDirection * 2 + 1;;
  1434.       } else /* style == PERIOD4 */ {
  1435.         randomDirection = NRAND(MAXORIENT / 2);
  1436.         if (randomDirection == 4)
  1437.           randomDirection = CW;
  1438.         else if (randomDirection == 5)
  1439.           randomDirection = CCW;
  1440.         else
  1441.           randomDirection = randomDirection * 2 + 1;
  1442.       }
  1443.       position = NRAND(w->oct.sizeSize);
  1444.     }
  1445.     MoveOct(w, face, position, randomDirection, style, FALSE);
  1446.     cb.reason = OCT_MOVED;
  1447.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1448.   }
  1449.   FlushMoves(w);
  1450.   cb.reason = OCT_RANDOMIZE;
  1451.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1452.   if (CheckSolved(w)) {
  1453.     cb.reason = OCT_SOLVED;
  1454.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1455.   }
  1456. }
  1457.  
  1458. static void MovePolyhedrons(w, face, rtt, direction, style)
  1459.   OctWidget w;
  1460.   int face;
  1461.   RTT rtt;
  1462.   int direction, style;
  1463. {
  1464.   int view, side, orient, newView, rotate, g, h, len;
  1465.   int newSide, oldSide, newDirection, bound, l = 0;
  1466.  
  1467.   view = face / MAXSIDES;
  1468.   side = face % MAXSIDES;
  1469.   if (style == PERIOD3) {
  1470.     if (direction == CW || direction == CCW) /* Remap to row movement */ {
  1471.       side = (side + 2) % MAXSIDES;
  1472.       direction = ((side + direction) % MAXSIDES) * 2;
  1473.       face = side + view * MAXSIDES;
  1474.       rtt.row = rtt.trbl = rtt.tlbr = 0;
  1475.     }
  1476.     if ((!rtt.row && !(direction % 2)) ||
  1477.         (!rtt.trbl && (direction % 2) && !((side + direction / 2) % 2)) ||
  1478.         (!rtt.tlbr && (direction % 2) && ((side + direction / 2) % 2)))
  1479.       RotateFace(w, view, rowToRotate[side][direction].face,
  1480.                  rowToRotate[side][direction].rotation);
  1481.     if ((rtt.row == w->oct.size - 1 && !(direction % 2)) ||
  1482.         (rtt.trbl == w->oct.size - 1 && (direction % 2) &&
  1483.           !((side + direction / 2) % 2)) ||
  1484.         (rtt.tlbr == w->oct.size - 1 && (direction % 2) &&
  1485.           (side + direction / 2) % 2))
  1486.       RotateFace(w, !view, rowToRotate[MAXSIDES + side][direction].face,
  1487.                  rowToRotate[MAXSIDES + side][direction].rotation);
  1488.     if (!(direction % 2))
  1489.       h = rtt.row;
  1490.     else if ((direction / 2 + side) % 2)
  1491.       h = rtt.tlbr;
  1492.     else /* (!((direction / 2 + side) % 2)) */
  1493.       h = rtt.trbl;
  1494.     if (w->oct.sticky && (h == 1 || h == 2)) {
  1495.       l = 0;
  1496.       bound = TRUE;
  1497.       h = 1;
  1498.     } else
  1499.       bound = FALSE;
  1500.     newView = view;
  1501.     newSide = side;
  1502.     newDirection = direction;
  1503.     do {
  1504.       len = Length(w, direction, h);
  1505.       rotate = rotateOrientP3[side][direction];
  1506.       ReadRTT(w, view, side, direction, h, len, 0);
  1507.       if (reverseP3[side][direction])
  1508.         ReverseRTT(w, len, 0);
  1509.       RotateRTT(w, rotate, len, 0);
  1510.       for (orient = 1; orient < 8; orient++) {
  1511.         if (slideNextRowP3[side][direction].viewChanged) {
  1512.            view = !view;
  1513.            h = w->oct.size - 1 - h;
  1514.         }
  1515.         oldSide = slideNextRowP3[side][direction].face;
  1516.         direction = slideNextRowP3[side][direction].direction;
  1517.         side = oldSide;
  1518.         len = Length(w, direction, h);
  1519.         rotate = rotateOrientP3[side][direction];
  1520.         if (orient < 6) {
  1521.           ReadRTT(w, view, side, direction, h, len, orient);
  1522.           if (reverseP3[side][direction])
  1523.             ReverseRTT(w, len, orient);
  1524.           RotateRTT(w, rotate, len, orient);
  1525.         }
  1526.         if (orient >= 2)
  1527.           WriteRTT(w, view, side, direction, h, len, orient - 2);
  1528.       }
  1529.       l++;
  1530.       h = 2;
  1531.       view = newView;
  1532.       side = newSide;
  1533.       direction = newDirection;
  1534.     } while (bound && l < 2);
  1535.   } else /* style == PERIOD4 */ {
  1536.     if (direction > TL)
  1537.       h = rtt.row;
  1538.     else if ((direction / 2 + side) % 2)
  1539.       h = rtt.tlbr;
  1540.     else /* (!((direction / 2 + side) % 2)) */
  1541.       h = rtt.trbl;
  1542.   
  1543.     if (w->oct.sticky &&
  1544.          !((direction > TL && h == w->oct.size - 1) || 
  1545.           (direction <= TL && !h))) {
  1546.       l = 0;
  1547.       h = (direction <= TL);
  1548.       bound = TRUE;
  1549.     } else
  1550.       bound = FALSE;
  1551.     g = 0;
  1552.     do /* In case this is on an edge */ {
  1553.       len = Length(w, direction, h);
  1554.       if (g == 1) {
  1555.         if (direction > TL) {
  1556.           direction = (direction == CW) ? CCW : CW;
  1557.           view = !view;
  1558.         } else
  1559.           side = (side + 2) % MAXSIDES;
  1560.       }
  1561.       ReadRTT(w, view, side, direction, h, len, 0);
  1562.       for (orient = 1; orient <= 4; orient++) {
  1563.         if (direction <= TL) {
  1564.           if ((side - direction / 2 + COORD) % MAXSIDES < 2) {
  1565.             newView = !view;
  1566.             newSide = (!(side % 2)) ? (side + 2) % MAXSIDES : side;
  1567.             newDirection = (!((direction / 2) % 2)) ?
  1568.               ((direction + 6) % MAXFACES) : ((direction + 2) % MAXFACES);
  1569.             if (!(side % 2))
  1570.               rotate = (((newDirection - direction) / 2 + MAXSIDES) % 
  1571.                 MAXSIDES == 1) ? 2 : MAXORIENT - 2;
  1572.             else
  1573.               rotate = (((newDirection - direction) / 2 + MAXSIDES) %
  1574.                 MAXSIDES == 1) ?  4 : MAXORIENT - 4;
  1575.           } else /* Next is on same view */ {
  1576.             newView = view;
  1577.             newSide = MAXSIDES - side - 1;
  1578.             if ((direction / 2) % 2 == 1) 
  1579.               newSide = (newSide + 2) % MAXSIDES;
  1580.             newDirection = direction;
  1581.             rotate = ((side - newSide + MAXSIDES) % MAXSIDES == 1) ?
  1582.               1 : MAXORIENT - 1;
  1583.           }
  1584.         } else /* direction == CW || direction == CCW */ {
  1585.           newView = view;
  1586.           newSide = (side + direction) % MAXSIDES;
  1587.           newDirection = direction;
  1588.           rotate = 3 * newDirection;
  1589.         }
  1590.         if (orient != 4)
  1591.           ReadRTT(w, newView, newSide, newDirection, h, len, orient);
  1592.         RotateRTT(w, rotate, len, orient - 1);
  1593.         if (direction <= TL)
  1594.           ReverseRTT(w, len, orient - 1);
  1595.         WriteRTT(w, newView, newSide, newDirection, h, len, orient - 1);
  1596.         view = newView;
  1597.         side = newSide;
  1598.         direction = newDirection;
  1599.       }
  1600.       l++;
  1601.       if (w->oct.sticky &&
  1602.           !((direction > TL && h == w->oct.size - 1) ||
  1603.           (direction <= TL && !h)))
  1604.         h++;
  1605.       else
  1606.         g++;
  1607.    } while ((bound && l < w->oct.size - 1) ||
  1608.             (((direction > TL && h == w->oct.size - 1) ||
  1609.               (direction <= TL && !h)) && g < 2 && !bound));
  1610.   }
  1611. }
  1612.  
  1613. static void RotateFace(w, view, side, direction)
  1614.   OctWidget w;
  1615.   int view, side, direction;
  1616. {
  1617.   int g, square, s;
  1618.   int i = 0, j = 0, k, i1, j1, k1, position;
  1619.  
  1620.   /* Read Face */
  1621.   k = -1;
  1622.   square = 0;
  1623.   for (g = 0; g < w->oct.sizeSize; g++) {
  1624.     /* This is the old algorithm, its now more efficient
  1625.     k = Sqrt(g);
  1626.     j = (g - k * k) / 2;
  1627.     i = ((k + 1) * (k + 1) - g - 1) / 2;*/
  1628.     if (square <= g) {
  1629.       k++;
  1630.       square = (k + 1) * (k + 1);
  1631.       j = -1;
  1632.       i = k;
  1633.     }
  1634.     if (!((square - g) % 2))
  1635.       i--;
  1636.     else
  1637.       j++;
  1638.     if (direction == CW) {
  1639.       k1 = w->oct.size - 1 - i;
  1640.       i1 = j;
  1641.       j1 = w->oct.size - 1 - k;
  1642.     } else /* (direction == CCW) */ {
  1643.       k1 = w->oct.size - 1 - j;
  1644.       j1 = i;
  1645.       i1 = w->oct.size - 1 - k;
  1646.     }
  1647.     position = k1 * k1 + 2 * j1 + (j1 != k1 - i1);
  1648.     w->oct.faceLoc[position] = w->oct.octaLoc[view * MAXSIDES + side][g];
  1649.   }
  1650.   /* Write Face */
  1651.   square = 1;
  1652.   s = 0;
  1653.   for (g = 0; g < w->oct.sizeSize; g++) {
  1654.     w->oct.octaLoc[view * MAXSIDES + side][g] = w->oct.faceLoc[g];
  1655.     w->oct.octaLoc[view * MAXSIDES + side][g].rotation = (direction == CW) ?
  1656.       (w->oct.octaLoc[view * MAXSIDES + side][g].rotation + 4) % MAXORIENT :
  1657.       (w->oct.octaLoc[view * MAXSIDES + side][g].rotation + 8) % MAXORIENT;
  1658.     DrawTriangle(w, view * MAXSIDES + side, g, FALSE);
  1659.     s = !s;
  1660.     if (g == square * square - 1) {
  1661.       s = 0;
  1662.       ++square;
  1663.     }
  1664.   }
  1665. }
  1666.  
  1667. static void ReadRTT(w, view, side, dir, h, len, orient)
  1668.   OctWidget w;
  1669.   int view, side, dir, h, len, orient;
  1670. {
  1671.   int f, g, s;
  1672.   int base = h * h;
  1673.  
  1674.   if (!(dir % 2) || dir > COORD)
  1675.     for (g = 0; g < len; g++)
  1676.       w->oct.rowLoc[orient][g] =
  1677.         w->oct.octaLoc[view * MAXSIDES + side][base + g];
  1678.   else if ((dir / 2 + side) % 2) {
  1679.     f = -1;
  1680.     for (g = 0; g < len; g++) {
  1681.       s = g % 2;
  1682.       w->oct.rowLoc[orient][g] =
  1683.         w->oct.octaLoc[view * MAXSIDES + side][base + f + !s];
  1684.       if (s == SAME)
  1685.         f += g + 2 * (h + 1) + 1;
  1686.     }
  1687.   } else {
  1688.     base += 2 * h;
  1689.     f = 1;
  1690.     for (g = 0; g < len; g++) {
  1691.       s = g % 2;
  1692.       w->oct.rowLoc[orient][g] =
  1693.         w->oct.octaLoc[view * MAXSIDES + side][base + f - !s];
  1694.       if (s == SAME)
  1695.         f += g + 2 * h + 1;
  1696.     }
  1697.   }
  1698. }
  1699.  
  1700. static void RotateRTT(w, rotate, len, orient)
  1701.   OctWidget w;
  1702.   int rotate, len, orient;
  1703. {
  1704.   int g;
  1705.  
  1706.   for (g = 0; g < len; g++)
  1707.     w->oct.rowLoc[orient][g].rotation =
  1708.       (w->oct.rowLoc[orient][g].rotation + rotate) % MAXORIENT;
  1709. }
  1710.  
  1711. static void ReverseRTT(w, len, orient)
  1712.   OctWidget w;
  1713.   int len, orient;
  1714. {
  1715.   int g;
  1716.   OctLoc temp;
  1717.  
  1718.   for (g = 0; g < (len - 1) / 2; g++) {
  1719.     temp = w->oct.rowLoc[orient][len - 1 - g];
  1720.     w->oct.rowLoc[orient][len - 1 - g] = w->oct.rowLoc[orient][g];
  1721.     w->oct.rowLoc[orient][g] = temp;
  1722.   }
  1723. }
  1724.  
  1725. static void WriteRTT(w, view, side, dir, h, len, orient)
  1726.   OctWidget w;
  1727.   int view, side, dir, h, len, orient;
  1728. {
  1729.   int f, g, s;
  1730.   int base = h * h;
  1731.  
  1732.   if (!(dir % 2) || dir > COORD) /* CW || CCW */ {
  1733.     for (g = 0; g < len; g++) {
  1734.       s = g % 2;
  1735.       w->oct.octaLoc[view * MAXSIDES + side][base + g] =
  1736.         w->oct.rowLoc[orient][g];
  1737.       DrawTriangle(w, view * MAXSIDES + side, base + g, FALSE);
  1738.     }
  1739.   } else if ((dir / 2 + side) % 2) {
  1740.     f = -1;
  1741.     for (g = 0; g < len; g++) {
  1742.       s = g % 2;
  1743.       w->oct.octaLoc[view * MAXSIDES + side][base + f + !s] =
  1744.         w->oct.rowLoc[orient][g];
  1745.       DrawTriangle(w, view * MAXSIDES + side, base + f + !s, FALSE);
  1746.       if (s == SAME)
  1747.         f += g + 2 * (h + 1) + 1;
  1748.     }
  1749.   } else {
  1750.     base += 2 * h;
  1751.     f = 1;
  1752.     for (g = 0; g < len; g++) {
  1753.       s = g % 2;
  1754.       w->oct.octaLoc[view * MAXSIDES + side][base + f - !s] =
  1755.         w->oct.rowLoc[orient][g];
  1756.       DrawTriangle(w, view * MAXSIDES + side, base + f - !s, FALSE);
  1757.       if (s == SAME)
  1758.         f += g + 2 * h + 1;
  1759.     }
  1760.   }
  1761. }
  1762.  
  1763. static void DrawFrame(w, gc)
  1764.   OctWidget w;
  1765.   GC gc;
  1766. {
  1767.   int startx, starty, lengthx, lengthy, longlength;
  1768.  
  1769.   startx = 1 + w->oct.puzzleOffset.x;
  1770.   starty = 1 + w->oct.puzzleOffset.y;
  1771.   lengthx = w->oct.viewLength - w->oct.delta + w->oct.puzzleOffset.x;
  1772.   lengthy = w->oct.viewLength - w->oct.delta + w->oct.puzzleOffset.y;
  1773.   XDrawLine(XtDisplay(w), XtWindow(w), gc, startx, starty, lengthx, starty);
  1774.   XDrawLine(XtDisplay(w), XtWindow(w), gc, startx, starty, startx, lengthy);
  1775.   XDrawLine(XtDisplay(w), XtWindow(w), gc, lengthx, starty, lengthx, lengthy);
  1776.   XDrawLine(XtDisplay(w), XtWindow(w), gc, startx, lengthy, lengthx, lengthy);
  1777.   XDrawLine(XtDisplay(w), XtWindow(w), gc, startx, lengthy, lengthx, starty);
  1778.   XDrawLine(XtDisplay(w), XtWindow(w), gc, startx, starty, lengthx, lengthy);
  1779.   if (w->oct.vertical) {
  1780.     longlength = 2 * w->oct.viewLength - 2 * w->oct.delta - 1 +
  1781.       w->oct.puzzleOffset.y;
  1782.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  1783.       startx, lengthy, startx, longlength);
  1784.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  1785.       lengthx, lengthy, lengthx, longlength);
  1786.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  1787.       startx, longlength, lengthx, longlength);
  1788.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  1789.       startx, longlength, lengthx, lengthy);
  1790.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  1791.       startx, lengthy, lengthx, longlength);
  1792.   } else {
  1793.     longlength = 2 * w->oct.viewLength - 2 * w->oct.delta - 1 +
  1794.       w->oct.puzzleOffset.x;
  1795.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  1796.       lengthx, starty, longlength, starty);
  1797.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  1798.       lengthx, lengthy, longlength, lengthy);
  1799.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  1800.       longlength, starty, longlength, lengthy);
  1801.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  1802.       longlength, starty, lengthx, lengthy);
  1803.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  1804.       lengthx, starty, longlength, lengthy);
  1805.   }
  1806. }   
  1807.  
  1808. void DrawAllPolyhedrons(w)
  1809.   OctWidget w;
  1810. {
  1811.   int position, face;
  1812.  
  1813.   for (face = 0; face < MAXFACES; face++)
  1814.     for (position = 0; position < w->oct.sizeSize; position++)
  1815.       DrawTriangle (w, face, position, FALSE);
  1816. }
  1817.  
  1818. static void DrawTriangle(w, face, position, offset)
  1819.   OctWidget w;
  1820.   int face, position, offset;
  1821. {
  1822.   int dx = 0, dy = 0;
  1823.   int side, row = Sqrt(position);
  1824.   int base = row * row;
  1825.   int g = position - base;
  1826.   int s = g % 2;
  1827.   int pos =  row * (w->oct.octaLength + w->oct.delta);
  1828.   int orient, view, faceOnView;
  1829.  
  1830.   view = face / MAXSIDES;
  1831.   faceOnView = face - view * MAXSIDES;
  1832.   orient = (!w->oct.vertical && view == DOWN) ?
  1833.     (faceOnView + MAXSIDES / 2) % MAXSIDES : faceOnView;
  1834.   switch (orient) {
  1835.     case 0:
  1836.       dy = w->oct.viewMiddle - w->oct.delta - 2 - pos;
  1837.       dx = w->oct.viewMiddle + pos - 1 - g * (w->oct.octaLength + w->oct.delta);
  1838.       break;
  1839.     case 1:
  1840.       dx = w->oct.viewMiddle + w->oct.delta + pos;
  1841.       dy = w->oct.viewMiddle + pos - 1 - g * (w->oct.octaLength + w->oct.delta);
  1842.       break;
  1843.     case 2:
  1844.       dy = w->oct.viewMiddle + w->oct.delta + pos;
  1845.       dx = w->oct.viewMiddle - pos - 1 + g * (w->oct.octaLength + w->oct.delta);
  1846.       break;
  1847.     case 3:
  1848.       dx = w->oct.viewMiddle - w->oct.delta - 2 - pos;
  1849.       dy = w->oct.viewMiddle - pos - 1 + g * (w->oct.octaLength + w->oct.delta);
  1850.       break;
  1851.     default:
  1852.       (void) printf ("DrawTriangle: orient %d\n", orient);
  1853.   }
  1854.   if (faceOnView % 2)
  1855.     side = ((faceOnView == 1) ? !s : s) * 2 + 1;
  1856.   else /* faceOnView == (RIGHT / 2) || faceOnView == (LEFT / 2) */
  1857.     side = ((!faceOnView) ? !s : s) * 2;
  1858.   side = (!w->oct.vertical && view == DOWN) ?
  1859.     (side + MAXSIDES / 2) % MAXSIDES : side;
  1860.   if (s == OPPOSITE)
  1861.     switch (side) {
  1862.       case 0:
  1863.         dy -= w->oct.octaLength;
  1864.         break;
  1865.       case 1:
  1866.         dx += w->oct.octaLength;
  1867.         break;
  1868.       case 2:
  1869.         dy += w->oct.octaLength;
  1870.         break;
  1871.       case 3:
  1872.         dx -= w->oct.octaLength;
  1873.         break;
  1874.       default:
  1875.         (void) printf ("DrawTriangle: side %d\n", side);
  1876.      }
  1877.   dx += w->oct.puzzleOffset.x;
  1878.   dy += w->oct.puzzleOffset.y;
  1879.   if (view == DOWN) {
  1880.     if (w->oct.vertical)
  1881.       dy += w->oct.viewLength - w->oct.delta - 1;
  1882.     else
  1883.       dx += w->oct.viewLength - w->oct.delta - 1;
  1884.   }
  1885.   triangleList[side][0].x = dx;
  1886.   triangleList[side][0].y = dy;
  1887.   if (offset) {
  1888.     XFillPolygon(XtDisplay(w), XtWindow(w),
  1889.       w->oct.borderGC,
  1890.       triangleList[side], 3, Convex, CoordModePrevious);
  1891.     XDrawLines(XtDisplay(w), XtWindow(w),
  1892.       w->oct.faceGC[w->oct.octaLoc[face][position].face],
  1893.       triangleList[side], 4, CoordModePrevious);
  1894.   } else {
  1895.     XFillPolygon(XtDisplay(w), XtWindow(w),
  1896.       w->oct.faceGC[w->oct.octaLoc[face][position].face],
  1897.       triangleList[side], 3, Convex, CoordModePrevious);
  1898.     XDrawLines(XtDisplay(w), XtWindow(w),
  1899.       w->oct.borderGC, triangleList[side], 4, CoordModePrevious);
  1900.   }
  1901.   if (w->oct.depth == 1 || w->oct.mono) {
  1902.     int letterX, letterY;
  1903.     char buf[2];
  1904.  
  1905.     (void) sprintf(buf, "%c", w->oct.faceName[w->oct.octaLoc
  1906.       [face][position].face][0]);
  1907.     letterX = dx + letterList[side].x;
  1908.     letterY = dy + letterList[side].y;
  1909.     XDrawString(XtDisplay(w), XtWindow(w), w->oct.inverseGC,
  1910.       letterX, letterY, buf, 1);
  1911.   }
  1912.   if (w->oct.orient)
  1913.     DrawOrientLine(w, w->oct.octaLoc[face][position].rotation, faceOnView,
  1914.       side, dx, dy);
  1915. }
  1916.  
  1917. static void DrawOrientLine(w, orient, face, side, dx, dy)
  1918.   OctWidget w;
  1919.   int orient, face, side, dx, dy;
  1920. {
  1921.   int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
  1922.   int temp1 = w->oct.octaLength + 1;
  1923.   int temp2 = w->oct.octaLength / 2 + 1;
  1924.   int temp3 = w->oct.orientLineLength / 3;
  1925.  
  1926.   /* clock positions */
  1927.   switch ((side == face) ? orient : (orient + MAXORIENT / 2) % MAXORIENT) {
  1928.     case 0:
  1929.       x2 = x1 = dx;
  1930.       y1 = dy + temp1;
  1931.       y2 = y1 - w->oct.orientLineLength;
  1932.       break;
  1933.     case 1:
  1934.       x1 = dx + temp2;
  1935.       y1 = dy + temp2;
  1936.       x2 = x1 + temp3;
  1937.       y2 = y1 - w->oct.orientLineLength;
  1938.       break;
  1939.     case 2:
  1940.       x1 = dx - temp2;
  1941.       y1 = dy - temp2;
  1942.       x2 = x1 + w->oct.orientLineLength;
  1943.       y2 = y1 - temp3;
  1944.       break;
  1945.     case 3:
  1946.       x1 = dx - temp1;
  1947.       x2 = x1 + w->oct.orientLineLength;
  1948.       y2 = y1 = dy;
  1949.       break;
  1950.     case 4:
  1951.       x1 = dx - temp2;
  1952.       y1 = dy + temp2;
  1953.       x2 = x1 + w->oct.orientLineLength;
  1954.       y2 = y1 + temp3;
  1955.       break;
  1956.     case 5:
  1957.       x1 = dx + temp2;
  1958.       y1 = dy - temp2;
  1959.       x2 = x1 + temp3;
  1960.       y2 = y1 + w->oct.orientLineLength;
  1961.       break;
  1962.     case 6:
  1963.       x2 = x1 = dx;
  1964.       y1 = dy - temp1;
  1965.       y2 = y1 + w->oct.orientLineLength;
  1966.       break;
  1967.     case 7:
  1968.       x1 = dx - temp2;
  1969.       y1 = dy - temp2;
  1970.       x2 = x1 - temp3;
  1971.       y2 = y1 + w->oct.orientLineLength;
  1972.       break;
  1973.     case 8:
  1974.       x1 = dx + temp2;
  1975.       y1 = dy + temp2;
  1976.       x2 = x1 - w->oct.orientLineLength;
  1977.       y2 = y1 + temp3;
  1978.       break;
  1979.     case 9:
  1980.       x1 = dx + temp1;
  1981.       x2 = x1 - w->oct.orientLineLength;
  1982.       y2 = y1 = dy;
  1983.       break;
  1984.     case 10:
  1985.       x1 = dx + temp2;
  1986.       y1 = dy - temp2;
  1987.       x2 = x1 - w->oct.orientLineLength;
  1988.       y2 = y1 - temp3;
  1989.       break;
  1990.     case 11:
  1991.       x1 = dx - temp2;
  1992.       y1 = dy + temp2;
  1993.       x2 = x1 - temp3;
  1994.       y2 = y1 - w->oct.orientLineLength;
  1995.       break;
  1996.     default:
  1997.       (void) printf("DrawOrientLine: orient %d\n", orient);
  1998.   }
  1999.   XDrawLine(XtDisplay(w), XtWindow(w), w->oct.inverseGC, x1, y1, x2, y2);
  2000. }
  2001.  
  2002. Boolean CheckSolved(w)
  2003.   OctWidget w;
  2004. {
  2005.   int face, position;
  2006.   OctLoc test;
  2007.  
  2008.   for (face = 0; face < MAXFACES; face++)
  2009.     for (position = 0; position < w->oct.sizeSize; position++) {
  2010.       if (!position) {
  2011.         test.face = w->oct.octaLoc[face][position].face;
  2012.         test.rotation = w->oct.octaLoc[face][position].rotation;
  2013.       } else if (test.face != /*MAXSIDES * view + face*/
  2014.                  w->oct.octaLoc[face][position].face ||
  2015.                  (w->oct.orient && test.rotation !=
  2016.                   w->oct.octaLoc[face][position].rotation))
  2017.         return FALSE;
  2018.   }
  2019.   return TRUE;
  2020. }
  2021.  
  2022. static int Length(w, dir, h)
  2023.   OctWidget w;
  2024.   int dir, h;
  2025. {
  2026.   if (!(dir % 2) || dir > COORD)
  2027.     return (2 * h + 1);
  2028.   else 
  2029.     return (2 * (w->oct.size - h) - 1);
  2030. }
  2031.  
  2032. static int CheckMoveDir(w, rtt1, rtt2, face, direction)
  2033.   OctWidget w;
  2034.   RTT rtt1, rtt2;
  2035.   int face, *direction;
  2036. {
  2037.   int which = -1, count = 0; 
  2038.   int i, *p1, *p2;
  2039.  
  2040.   p1 = &(rtt1.row);
  2041.   p2 = &(rtt2.row);
  2042.   for (i = 0; i < 3; i++, p1++, p2++)
  2043.     if (*p1 == *p2) {
  2044.       which = i;
  2045.       count++;
  2046.     }
  2047.   if (count == 1)
  2048.     switch (which) {
  2049.       case 0: /* ROW */
  2050.         if (rtt2.trbl > rtt1.trbl)
  2051.           *direction = (2 * face + LEFT) % COORD;
  2052.         else
  2053.           *direction = (2 * face + RIGHT) % COORD;
  2054.         break;
  2055.       case 1: /* TRBL */
  2056.         if (rtt2.row > rtt1.row)
  2057.           *direction = (2 * face + TR) % COORD;
  2058.         else
  2059.           *direction = (2 * face + BL) % COORD;
  2060.         break;
  2061.       case 2: /* TLBR */
  2062.         if (rtt2.row > rtt1.row)
  2063.           *direction = (2 * face + TL) % COORD;
  2064.         else
  2065.           *direction = (2 * face + BR) % COORD;
  2066.         break;
  2067.     }
  2068.   if (!w->oct.vertical && face >= MAXSIDES && *direction > TL)
  2069.     *direction = (*direction + MAXSIDES) % MAXFACES;
  2070.   return count;
  2071. }
  2072.  
  2073. static RTT ToRTT(position)
  2074.   int position;
  2075. {
  2076.   RTT rtt;
  2077.  
  2078.   rtt.row = Sqrt(position);
  2079.   /* Passing row so there is no sqrt calculation again */
  2080.   rtt.trbl = (position - rtt.row * rtt.row) / 2;
  2081.   rtt.tlbr = (rtt.row * rtt.row + 2 * rtt.row - position) / 2;
  2082.   return rtt;
  2083. }
  2084.  
  2085. static int ToPosition(rtt)
  2086.   RTT rtt;
  2087. {
  2088.   return (rtt.row * rtt.row + rtt.row + rtt.trbl - rtt.tlbr);
  2089. }
  2090.  
  2091. /* This is fast for small i, a -1 is returned for negative i. */
  2092. static int Sqrt(i)
  2093.   int i;
  2094. {
  2095.   int j = 0;
  2096.  
  2097.   while (j * j <= i)
  2098.     j++;
  2099.   return (j - 1);
  2100. }
  2101.  
  2102. #ifdef DEBUG
  2103.  
  2104. static void PrintOcta(w)
  2105.   OctWidget w;
  2106. {
  2107.   int face, position, square;
  2108.  
  2109.   for (face = 0; face < MAXSIDES; face++) {
  2110.     square = 1;
  2111.     for (position = 0; position < w->oct.sizeSize; position++) {
  2112.       (void) printf("%d %d  ",
  2113.                 w->oct.octaLoc[face][position].face,
  2114.                 w->oct.octaLoc[face][position].rotation);
  2115.        if (position == square * square - 1) {
  2116.          (void) printf("\n");
  2117.          ++square;
  2118.        }
  2119.     }
  2120.     (void) printf("\n");
  2121.   }
  2122.   (void) printf("\n");
  2123. }
  2124.  
  2125. static void PrintFace(w)
  2126.   OctWidget w;
  2127. {
  2128.   int position;
  2129.   int square = 1;
  2130.  
  2131.   for (position = 0; position < w->oct.sizeSize; position++) {
  2132.     (void) printf("%d %d  ",
  2133.              w->oct.faceLoc[position].face,
  2134.              w->oct.faceLoc[position].rotation);
  2135.     if (position == square * square - 1) {
  2136.       (void) printf("\n");
  2137.       ++square;
  2138.     }
  2139.   }
  2140.   (void) printf("\n");
  2141. }
  2142.  
  2143. static void PrintRow(w, len, orient)
  2144.   OctWidget w;
  2145.   int len, orient;
  2146. {
  2147.   int i;
  2148.  
  2149.   (void) printf("Row %d:\n", orient);
  2150.   for (i = 0; i < len; i++)
  2151.     (void) printf("%d %d  ", w->oct.rowLoc[orient][i].face,
  2152.             w->oct.rowLoc[orient][i].rotation);
  2153.   (void) printf("\n");
  2154. }
  2155.  
  2156. #endif
  2157.